home *** CD-ROM | disk | FTP | other *** search
-
-
-
- 41
-
- CHAPTER 6 - MULTIPLICATION AND DIVISION
-
-
-
- Unlike addition and subtraction, where the result can be in
- either memory or in one of the registers, the multiplication and
- division instructions have a rigid format.
-
-
- MULTIPLICATION
-
- You can multiply a one byte number by a one byte number and get a
- two byte result, or you can multiply a one word number by a one
- word number and get a two word result. The first number MUST be
- in AL for the byte operation or in AX for the word operation. The
- second number may be a register or a memory location (but not a
- constant). The result is in AH:AL for the byte operation and
- DX:AX for the word operation. Our possibilities are:
-
- AL X (one byte register or memory) -> AH:AL
- AX X (one word register or memory) -> DX:AX
-
- Is there a difference between signed and unsigned numbers? Yes, a
- very big difference. For the byte operation FFh = -1 signed but
- FFh = 255 unsigned. -1 X -1 = 1 = 0001h. 255 X 255 = 65025 =
- FE01h. These are two completely different answers. You need to
- tell the 8086 whether you want signed multiplication or unsigned
- multiplication. The 8086 does the rest. Let's look at both signed
- and unsigned multiplication. We'll do byte multiplication for
- unsigned numbers and word multiplication for signed numbers. The
- instruction for unsigned multiplication is MUL. The instruction
- for signed multiplication is IMUL. AX or AL is understood to be
- the register, so it is not in the code. The instructions are:
-
- variable1 db ?
- variable2 dw ?
-
- mul bx ; unsigned word from a register
- mul variable1 ; unsigned byte from memory
- imul ch ; signed byte from a register
- imul variable2 ; signed word from memory
-
- No AX or AL. It's understood. Here's our program:
-
- template.asm
- ; + + + + + + + + + + + + + + + START DATA BELOW THIS LINE
- answer1 dw ?
- answer2 dw ?
- ; + + + + + + + + + + + + + + + END DATA ABOVE THIS LINE
-
- ; - - - - - START CODE BELOW THIS LINE
-
- mov cx, 0 ; clear cx for visual effect
-
- ______________________
-
- The PC Assembler Tutor - Copyright (C) 1989 Chuck Nelson
-
-
-
-
- The PC Assembler Tutor 42
- ______________________
-
-
- outer_loop:
- ; unsigned byte multiplication
- mov ax_byte, 0A2h ; half regs, unsigned
- mov bx_byte, 0A2h ; half regs, unsigned
- lea ax, ax_byte
- call set_reg_style
-
- mov ax, 0 ; clear regs
- mov bx, 0
- mov dx, 0
- call show_regs
-
- call get_unsigned_byte ; get two unsigned bytes
- call show_regs
- push ax ; save the first number
- call get_unsigned_byte
- mov bl, al
- pop ax ; restore the first number
- call show_regs_and_wait
- mul bl ; unsigned multiplication
- call print_unsigned ; display the result (ax)
- call show_regs_and_wait
-
-
- ; signed word multiplication
- mov ax_byte, 01h ; full reg, signed
- mov bx_byte, 01h
- mov dx_byte, 01h
- lea ax, ax_byte
- call set_reg_style
-
- mov ax, 0 ; clear regs
- mov bx, 0
- call show_regs
-
- call get_signed ; get two numbers
- call show_regs
- push ax ; save the first number
- call get_signed
- mov bx, ax
- pop ax ; restore the first number
- call show_regs_and_wait
- imul bx ; signed multiplication
- push ax ; save result
- mov answer1, ax ; display 4 byte result
- mov answer2, dx
- lea ax, answer1
- call print_signed_4byte
- pop ax ; restore result
- call show_regs_and_wait
-
- jmp outer_loop
- ; - - - - - END CODE ABOVE THIS LINE
-
- If the answer for the unsigned byte multiplication is greater
- than 255, it will be difficult to read the answer from the half
-
-
-
-
- Chapter 6 - Multiplication and Division 43
- _______________________________________
-
- registers, so we print out the whole AX register.
-
- If the answer for the signed word multiplication is greater than
- +32767 or is less than -32768, the answer will be unreadable in
- the DX:AX registers. We move the answer to memory, and then call
- print_signed_4byte. As with set_reg_style, the data is too long
- to be put in AX, so we pass the address of the first byte of
- data with:
-
- lea ax, answer1
-
- and then call print_signed_4byte. Everything from PUSH AX to POP
- AX is designed to do that.
-
- Do MUL and IMUL set any flags? Yes. For byte multiplication, if
- AL contains the total answer, the 8086 clears the OF and CF
- flags. If part of the answer is in AH, then the 8086 sets both
- the OF and CF flags. For word multiplication, if AX contains the
- total answer, the 8086 clears the OF and CF flags. If part of the
- answer is in DX, then the 8086 sets both the OF and CF flags.
-
- What do we mean by the total answer? This is simple for unsigned
- multiplication. If AH (or DX for word) is 0, then the total
- answer is in AL (or AX for word). It is more complicated for
- signed multiplication. Consider word multiplication. +30000 X +2
- = +60000. But that's less than 65536, so it is completely
- contained in AX, right? WRONG. The leftmost bit of AX contains
- the sign. If the signed result is out of the range -32768 to
- +32767, information about the absolute value of the number is
- corrupting information about the sign of the number. AX will
- have the wrong number and the wrong sign. Only by combining AX
- with DX will you get the correct answer. Similarly for byte
- multiplication with AL, if the result is not in the range -128 to
- +127, The leftmost (sign) bit will be corrupted, and only by
- looking at AH:AL will you be able to get the correct result.
-
- If CF and OF are set, you need to look at both registers to
- evaluate the number. You might want to do error handling, so once
- again, you can have:
-
- mul bx
- jnc go_on
- call error_handler
- go_on:
-
- using the same reverse logic as before (if nothing is wrong, skip
- the error handler). We can also use:
-
- mul bx
- into
-
- if there is an INTO error handler.
-
-
- DIVISION
-
- Division operates in the same way as multiplication. Word
-
-
-
-
- The PC Assembler Tutor 44
- ______________________
-
- division operates on the DX:AX pair and byte division operates on
- the AH:AL pair. There are two instructions, DIV for unsigned
- division and IDIV for signed division. After the division:
-
- byte AL = quotient, AH = remainder
- word AX = quotient, DX = remainder
-
- Both DIV and IDIV operate on BOTH registers. For bytes, they
- consider AH:AL a single number. This means that AH must be set
- correctly before the division or you will get an incorrect
- answer. For words, they consider DX:AX a single number. This
- means that DX must be set correctly before the division, or the
- result will be incorrect. Why did Intel include AH and DX in the
- division? Wouldn't it have been easier to use just AH (or AX for
- word division) and put the quotient and remainder in the same
- place? These instructions are actually designed for dividing a
- long number (4 or 8 bytes). How it works is pretty slick; you'll
- find out about it later in the book.
-
- How do you set AH and DX correctly? For unsigned numbers, that's
- easy. Make them 0:
-
- mov al, variable
- mov ah, 0
- div cl ; unsigned byte division
-
- For signed division, set AH or DX to 0 (0000h) if it is a
- positive number and set them to -1 (FFFFh) if the number is
- negative. This is just standard sign extension that was covered
- in the chapter on numbers. Fortunately for us, Intel has provided
- instructions which do the sign extension for us. CBW (convert
- byte to word) correctly extends the signed number in AL through
- AH:AL. CWD (convert word to double) correctly extends the signed
- number in AX through DX:AX. The code is
-
- mov ax, variable5
- cwd
- idiv bx ; signed word division
-
- Of course with these two instructions you can convert a byte to a
- double word.
-
- mov al, variable6
- cbw
- cwd
- idiv bx ; signed word division
-
- first converting to a word, then to a double word.
-
- For the division program, we are going to use the multiplication
- program and make some small changes. Make a copy of your
- multiplication program:
-
- >copy mult.asm div.asm
-
- and then make the following changes:
-
-
-
-
-
- Chapter 6 - Multiplication and Division 45
- _______________________________________
-
- MULTIPLICATION DIVISION
-
- ; unsigned byte ; unsigned byte
- pop ax
- pop ax mov ah, 0
- call show_regs_and_wait call show_regs_and_wait
- mul bl div bl
-
-
- ; signed word ; signed word
- pop ax
- pop ax cwd
- call show_regs_and_wait call show_regs_and_wait
- imul bx idiv bx
-
- The calls to print_unsigned and print_signed_4byte are
- irrelevant, so you may either delete them or ignore the output.
- All we did was change the multiplication instruction to division
- and prepare the upper register correctly (AH for byte, DX for
- word). That's all.
-
- Assemble, link, and run it. Try out both positive and negative
- numbers and see what the remainder looks like. Also notice the
- sign extension just before the division. Remember, for division,
- the results are in the following places:
-
- byte AL = quotient, AH = remainder
- word AX = quotient, DX = remainder
-
- Now divide by 0. Ka-pow! You should have exited the program and
- gotten an error message. Unlike the other arithmetical errors
- where you have the option of ignoring them or making an error
- handler for them, the 8086 considers division by 0 a major no-no.
- When the 8086 detects division by zero,{1} it interrupts the
- program and goes to the zero-divide handler (which is external to
- the program). Normally, this just exits the program since the
- data is now worthless.
-
-
-
-
-
-
- ____________________
-
- 1 What it actually detects is that the quotient is too large to
- fit in the lower register (AL for byte or AX for word). As long
- as the upper register is correctly sign extended, the only time
- this can happen is when you divide by 0. If the upper register is
- NOT sign extended correctly, you can have zero divide errors all
- over the place, even though you aren't dividing by 0. As an
- example, if AH:AL contain 3275 and bl contains 10, then:
-
- div bl
-
- will give a quotient of 327 ( > 255) and will generate a zero
- divide error.
-
-
-
-
- The PC Assembler Tutor 46
- ______________________
-
- SUMMARY
-
- MUL and IMUL
- MUL performs unsigned multiplication and IMUL performs
- signed multiplication. For bytes, the multiplicand is in AL
- and the result is in the AH:AL pair. For words, the
- multiplicand is in AX and the result is in the DX:AX pair.
- If the total result is contained in the lower register, CF
- and OF are cleared (0). If part of the result is in the
- upper register, CF and OF are set (1). The multiplier may be
- either a register or a variable in memory.
-
- variable1 db ?
- variable2 dw ?
-
- mul variable1 ; unsigned byte
- mul cx ; unsigned word
- imul bl ; signed byte
- imul variable2 ; signed word
-
-
- DIV and IDIV
- DIV performs unsigned division. IDIV performs signed
- division. For bytes, the dividend is the AH:AL pair. For
- words, the dividend is the DX:AX pair. In byte division, AH
- must be correctly prepared before the division. For word
- division, DX must be correctly prepared before the division.
- The divisor may be either a register or a variable in
- memory.
-
- variable1 db ?
- variable2 dw ?
-
- div variable1 ; unsigned byte
- div cx ; unsigned word
- idiv bl ; signed byte
- idiv variable2 ; signed word
-
- The quotient and remainder are as follows:
-
- byte AL = quotient, AH = remainder
- word AX = quotient, DX = remainder
-
- No flags are affected. If the quotient is too large for the
- lower register, or if you divide by zero, a zero divide
- program interrupt occurs.
-
- CORRECT SIGN EXTENSION
- To prepare for division, you must correctly sign extend the
- lower register into the upper register. For unsigned
- division, zero the upper register (AH = 0 or DX = 0). For
- signed division, use CBW and CWD. CBW (convert byte to word)
- extends a signed number in AL through AH:AL. CWD (convert
- word to double) extends a signed number in AX through DX:AX
-
-